<meta charset="utf-8">
(#) Avoid using old K1 Kotlin compiler APIs

!!! WARNING: Avoid using old K1 Kotlin compiler APIs
   This is a warning.

Id
:   `KotlincFE10`
Summary
:   Avoid using old K1 Kotlin compiler APIs
Note
:   **This issue is disabled by default**; use `--enable KotlincFE10`
Severity
:   Warning
Category
:   Lint Implementation Issues
Platform
:   JDK
Vendor
:   Android Open Source Project
Feedback
:   https://issuetracker.google.com/issues/new?component=192708
Since
:   8.1.0 (July 2023)
Affects
:   Kotlin and Java files
Editing
:   This check runs on the fly in the IDE editor
Implementation
:   [Source Code](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/KotlincFE10Detector.kt)
Tests
:   [Source Code](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/KotlincFE10DetectorTest.kt)

K2, the new version of Kotlin compiler, which encompasses the new
frontend, is coming. Try to avoid using internal APIs from the old
frontend if possible.

(##) Example

Here is an example of lint warnings produced by this check:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~text
src/test/pkg/TestVisitor.kt:28:Warning:
org.jetbrains.kotlin.resolve.BindingContext appears to be part of the
old K1 Kotlin compiler. Avoid using it if possible; K1 will be going
away soon. [KotlincFE10]
    val bindingContext = service.getBindingContext(declaration) // ERROR
                         --------------------------------------
src/test/pkg/TestVisitor.kt:29:Warning:
org.jetbrains.kotlin.resolve.BindingContext appears to be part of the
old K1 Kotlin compiler. Avoid using it if possible; K1 will be going
away soon. [KotlincFE10]
    val type = bindingContext.getType(expression) ?: return // ERROR
               --------------
src/test/pkg/TestVisitor.kt:30:Warning:
org.jetbrains.kotlin.types.KotlinType appears to be part of the old K1
Kotlin compiler. Avoid using it if possible; K1 will be going away soon.
[KotlincFE10]
    if (type.isDynamic()) return // ERROR
        ----
src/test/pkg/TestVisitor.kt:37:Warning:
org.jetbrains.kotlin.resolve.BindingContext appears to be part of the
old K1 Kotlin compiler. Avoid using it if possible; K1 will be going
away soon. [KotlincFE10]
    bindingContext: BindingContext, // ERROR
                    --------------
src/test/pkg/TestVisitor.kt:41:Warning:
org.jetbrains.kotlin.resolve.BindingContext appears to be part of the
old K1 Kotlin compiler. Avoid using it if possible; K1 will be going
away soon. [KotlincFE10]
    val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, node.sourcePsi) // ERROR
                     --------------
src/test/pkg/TestVisitor.kt:42:Warning:
org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
appears to be part of the old K1 Kotlin compiler. Avoid using it if
possible; K1 will be going away soon. [KotlincFE10]
    if (descriptor is DeclarationDescriptorWithVisibility) { // ERROR
                      -----------------------------------
src/test/pkg/TestVisitor.kt:43:Warning:
org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
appears to be part of the old K1 Kotlin compiler. Avoid using it if
possible; K1 will be going away soon. [KotlincFE10]
    val effectiveVisibility = descriptor.visibility.effectiveVisibility(descriptor, false) // ERROR
                                         ----------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here is the source file referenced above:

`src/test/pkg/TestVisitor.kt`:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin linenumbers
package test.pkg

import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.JavaContext
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.effectiveVisibility
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService

class TestVisitor(val context: JavaContext) : UElementHandler() {
    // Example from [InteroperabilityDetector.KotlinVisitor#visitMethod]
    override fun visitMethod(node: UMethod) {
        val declaration = node.sourcePsi as? KtCallableDeclaration ?: return
        val expression = when (declaration) {
          is KtProperty -> declaration.initializer ?: declaration.delegateExpression ?: return
          is KtFunction -> declaration.bodyExpression ?: declaration.bodyBlockExpression ?: return
          else -> return
        }
        val service = declaration.project.getService(KotlinUastResolveProviderService::class.java)
        val bindingContext = service.getBindingContext(declaration) // ERROR
        val type = bindingContext.getType(expression) ?: return // ERROR
        if (type.isDynamic()) return // ERROR
        // report something at the end
    }

    // Example from [PsiModifierItem#computeFlag] in Metalava
    private fun computeFlag(
        node: UElement,
        bindingContext: BindingContext, // ERROR
    ) : Int {
        var visibilityFlag = PACKAGE_PRIVATE
        if (node.sourcePsi is KtElement) {
            val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, node.sourcePsi) // ERROR
            if (descriptor is DeclarationDescriptorWithVisibility) { // ERROR
                val effectiveVisibility = descriptor.visibility.effectiveVisibility(descriptor, false) // ERROR
                if (effectiveVisibility == EffectiveVisibility.Internal) {
                    visibilityFlag = INTERNAL
                }
            }
        }
        return visibilityFlag
    }

    companion object {
        private const val INTERNAL = 1
        private const val PACKAGE_PRIVATE = 2
    }
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can also visit the
[source code](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/KotlincFE10DetectorTest.kt)
for the unit tests for this check to see additional scenarios.

(##) Suppressing

You can suppress false positives using one of the following mechanisms:

* Using a suppression annotation like this on the enclosing
  element:

  ```kt
  // Kotlin
  @Suppress("KotlincFE10")
  fun method() {
     problematicStatement()
  }
  ```

  or

  ```java
  // Java
  @SuppressWarnings("KotlincFE10")
  void method() {
     problematicStatement();
  }
  ```

* Using a suppression comment like this on the line above:

  ```kt
  //noinspection KotlincFE10
  problematicStatement()
  ```

* Using a special `lint.xml` file in the source tree which turns off
  the check in that folder and any sub folder. A simple file might look
  like this:
  ```xml
  &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;lint&gt;
      &lt;issue id="KotlincFE10" severity="ignore" /&gt;
  &lt;/lint&gt;
  ```
  Instead of `ignore` you can also change the severity here, for
  example from `error` to `warning`. You can find additional
  documentation on how to filter issues by path, regular expression and
  so on
  [here](https://googlesamples.github.io/android-custom-lint-rules/usage/lintxml.md.html).

* In Gradle projects, using the DSL syntax to configure lint. For
  example, you can use something like
  ```gradle
  lintOptions {
      disable 'KotlincFE10'
  }
  ```
  In Android projects this should be nested inside an `android { }`
  block.

* For manual invocations of `lint`, using the `--ignore` flag:
  ```
  $ lint --ignore KotlincFE10 ...`
  ```

* Last, but not least, using baselines, as discussed
  [here](https://googlesamples.github.io/android-custom-lint-rules/usage/baselines.md.html).

<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js" charset="utf-8"></script><script src="https://morgan3d.github.io/markdeep/latest/markdeep.min.js" charset="utf-8"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>